#include <iostream>
#include <string>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;

const size_t default_buffer_size = 128;

void usage(const string &args) {
    cout << "Usage: " << args << " server_ip server_port\n\t" << args << " 122.51.150.41 8080" << endl;
}

int init(char *argv[]) {
    string server_ip = argv[1];
    uint16_t server_port = stoi(argv[2]);
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0) {
        perror("socket err");
        return errno;
    }
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    if(inet_pton(AF_INET, server_ip.c_str(), &server_addr.sin_addr) != 1) {
        perror("inet_pton err");
        return errno;
    }

    // 客户端的端口绑定由系统随机选择
    // 在第一次尝试连接服务器时发生
    if(connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("connect err");
        return errno;
    }

    return sockfd;
}

void chat_with_server(int sockfd) {
    while(true) {
        cout << "[client say]@ ";
        string msg;
        getline(cin, msg);
        // 发送给服务器
        ssize_t n = write(sockfd, msg.c_str(), msg.size());
        if(n <= 0) {
            if(n == -1) {
                perror("write err");
                break;
            }
            continue;
        }
        // 接收服务器的回复
        char out_buff[default_buffer_size];
        n = read(sockfd, out_buff, sizeof(out_buff) - 1);
        if(n <= 0) {
            if(n == 0) {
                cout << "end of file, client close" << endl;
                break;
            }
            else {
                perror("read err");
                exit(errno);
            }
        }
        out_buff[n] = '\0';
        string msg_from_server = out_buff;
        cout << msg_from_server << endl;
    }
}

int main(int argc, char *argv[]) {
    if(argc != 3) {
        usage(argv[0]);
        return -1;
    }
    
    int sockfd = init(argv);
    
    chat_with_server(sockfd);

    close(sockfd);
    return 0;
}